package main

import (
	"encoding/json"
	"errors"
	"fmt"
	"io/ioutil"
	"net/http"
)

const WxUrl string = "https://api.weixin.qq.com/cgi-bin"

type WxClientError struct {
	ErrCode int    `json:"errcode"`
	ErrMsg  string `json:"errmsg"`
}

type WxClient struct {
	AppID  string
	Secret string

	AccessToken string
	OpenID      string
}

func NewWxClient(appid, secret string) *WxClient {
	wc := WxClient{AppID: appid, Secret: secret}
	return &wc
}

type WxAccessTokenT struct {
	WxClientError
	AccessToken  string `json:"access_token"`
	ExpiresIn    int    `json:"expires_in"`
	RefreshToken string `json:"refresh_token"`
	OpenID       string `json:"openid"`
	Scope        string `json:"scope"`
}

func (p *WxClient) GetAccessToken(code string) (err error) {
	const URLTemplate string = "https://api.weixin.qq.com/sns/oauth2/access_token?appid=%s&secret=%s&code=%s&grant_type=authorization_code"
	url := fmt.Sprintf(URLTemplate, p.AppID, p.Secret, code)
	var res []byte
	res, err = p.get(url)
	if err != nil {
		return err
	}
	var at WxAccessTokenT
	err = json.Unmarshal(res, &at)
	if err == nil {
		if at.ErrCode != 0 {
			err = errors.New(at.ErrMsg)
			return
		}
		p.AccessToken = at.AccessToken
		p.OpenID = at.OpenID
	}

	return
}

type UserInfoT struct {
	OpenID     string `json:"openid"`
	NickName   string `json:"nickname"`
	Sex        int    `json:"sex"`
	Province   string `json:"province"`
	City       string `json:"city"`
	Country    string `json:"country"`
	HeadImgURL string `json:"headimgurl"`
	UnionID    string `json:"unionid"`
}

func (p *WxClient) GetUserInfo() (*UserInfoT, error) {
	const URLTemplate string = "https://api.weixin.qq.com/sns/userinfo?access_token=%s&openid=%s&lang=zh_CN"
	url := fmt.Sprintf(URLTemplate, p.AccessToken, p.OpenID)
	var res []byte
	var err error

	res, err = p.get(url)
	if err != nil {
		return nil, err
	}
	//zLog(nil, "GetUserInfo返回内容：", string(res))
	var ui UserInfoT
	err = json.Unmarshal(res, &ui)
	if err != nil {
		return nil, err
	}
	return &ui, nil
}

func (p *WxClient) get(url string) ([]byte, error) {
	resp, err := http.Get(url)
	if err != nil {
		return nil, err
	}
	defer resp.Body.Close()

	return ioutil.ReadAll(resp.Body)
}
